// 代码题

// 一、
function getPromise(value) {
    return new Promise((resolve) => {
        setTimeout(resolve, 10, value);
    });
}

const p1 = getPromise("hello");

p1.then((value) => {
    return getPromise(value + " lagou");
}).then((value) => {
    setTimeout(console.log, 10, value, "I ♥ U");
})

// 二、
var _ = require('lodash');
// Load the core build.
var _ = require('lodash/core');
// Load the FP build for immutable auto-curried iteratee-first data-last methods.
var fp = require('lodash/fp');

const cars = [{
    name: "Ferrari FF",
    horsepower: 600,
    dollar_vale: 700000,
    in_stock: 648000
}, {
    name: "Spyker C12 Zagato",
    horsepower: 650,
    dollar_vale: 648000,
    in_stock: false
}, {
    name: "Jaquar XKR-S",
    horsepower: 550,
    dollar_vale: 132000,
    in_stock: false
}, {
    name: "Audi R8",
    horsepower: 525,
    dollar_vale: 114200,
    in_stock: false
}, {
    name: "Aston Martin One-77",
    horsepower: 750,
    dollar_vale: 1850000,
    in_stock: true
}, {
    name: "Pagani Huayra",
    horsepower: 700,
    dollar_vale: 1300000,
    in_stock: false
}];

// 1)
const getLastInStock = fp.flowRight(fp.prop("in_stock"), fp.last);
console.log(getLastInStock(cars));

// 2)
const getFirstInStock = fp.flowRight(fp.prop("name"), fp.first);
console.log(getFirstInStock(cars));

// 3)
let _average = function (xs) {
    return fp.reduce(fp.add, 0, xs) / xs.length;
}

const averageDollarValue = fp.flowRight(_average, fp.map(car => car.dollar_vale));
console.log(averageDollarValue(cars));

// 4)
let _underscore = fp.replace(/\W+/g, "_");

const sanitizeNames = fp.map(fp.flowRight(fp.toLower, _underscore));
console.log(sanitizeNames(["A b", "C d"]));

// 三、
class Container {
    static of(value) {
        return new Container(value);
    }

    constructor(value) {
        this._value = value;
    }

    map(fn) {
        return Container.of(fn(this._value));
    }
}

class Maybe {
    static of(value) {
        return new Maybe(value);
    }

    constructor(value) {
        this._value = value;
    }

    map(fn) {
        return this.isNothing() ? this : Maybe.of(fn(this._value));
    }

    isNothing() {
        return this._value === null || this._value === undefined;
    }
}

// 1)
let maybe = Maybe.of([5, 6, 1]);
// console.log(maybe.map(fp.map(fp.add(1)))._value);
let ex1 = (value) => {
    return fp.map(fp.add(1))(value);
}

console.log(maybe.map(ex1)._value);

// 2)
let xs = Container.of(["do", "ray", "me"]);
// console.log(xs.map(fp.first)._value);
let ex2 = (value) => {
    return fp.first(value);
}

console.log(xs.map(ex2)._value);

// 3)
let safeProp = fp.curry(function (x, o) {
    return Maybe.of(o[x]);
})

let user = { id: 2, name: "Albert" };

// console.log(safeProp("name")(user).map(fp.first)._value);

let ex3 = () => {
    return safeProp("name")(user).map(fp.first)._value;
}
console.log(ex3());

// 4)
let ex4 = (n) => {
    return Maybe.of(n).map(parseInt)._value;
}

console.log(ex4());

// 四、
class myPromise {
    // promise 状态
    statuse = "pending";
    // 成功后的值
    valuel = undefined;
    // 失败后的原因
    reason = undefined;
    // 回调
    successCallbackArr = [];
    failCallbackArr = []

    constructor(executor) {
        const resolve = (value) => {
            // 如果状态不是 pending, 则跳出
            if (this.statuse !== "pending") return;

            // 更改状态、保存值
            this.statuse = "fulfilled";
            this.value = value;

            while (this.successCallbackArr.length) this.successCallbackArr.shift()()

        }

        const reject = (reason) => {
            // 如果状态不是 pending, 则跳出
            this.statuse === "pending" && (this.statuse = "rejected");

            // 更改状态、保存值
            this.statuse = "rejected";
            this.reason = reason;

            while (this.failCallbackArr.length) this.failCallbackArr.shift()()
        };

        executor(resolve, reject);
    }

    then(successCallback, failCallback) {
        // 参数可选
        successCallback = successCallback instanceof Function ? successCallback : value => value;
        failCallback = failCallback instanceof Function ? failCallback : reason => { throw reason };

        let thenPromise = new myPromise((resolve, reject) => {
            if (this.statuse === "fulfilled") {
                setTimeout(() => {
                    let callBackValue = successCallback(this.value);
                    // 判断 x 的值是普通值还是promise对象
                    // 如果是普通值 直接调用resolve 
                    // 如果是promise对象 查看promsie对象返回的结果 
                    // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                    myPromise.resolvePromise(thenPromise, callBackValue, resolve, reject);
                }, 0);
            } else if (this.statuse === "rejected") {
                setTimeout(() => {
                    let callBackValue = failCallback(this.value);
                    myPromise.resolvePromise(thenPromise, callBackValue, resolve, reject);
                }, 0);
            } else {
                setTimeout(() => {
                    this.successCallbackArr.push(() => {
                        try {
                            let callBackValue = successCallback(this.value);
                            myPromise.resolvePromise(thenPromise, callBackValue, resolve, reject);
                        } catch (err) {
                            reject(e);
                        }
                    })

                    this.failCallbackArr.push(() => {
                        try {
                            let callBackValue = failCallback(this.value);
                            myPromise.resolvePromise(thenPromise, callBackValue, resolve, reject);
                        } catch (err) {
                            reject(e);
                        }
                    })
                }, 0);
            }
        });

        return thenPromise;
    }

    finally(callback) {
        return this.then(value => {
            return myPromise.resolve(callback()).then(() => value);
        }, reason => {
            return myPromise.resolve(callback()).then(() => { throw reason })
        })
    }

    catch(failCallback) {
        return this.then(undefined, failCallback)
    }

    static all(array) {
        let result = [];
        let index = 0;
        return new myPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;
                index++;
                if (index === array.length) {
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof myPromise) {
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    addData(i, array[i]);
                }
            }
        })
    }

    static resolve(value) {
        if (value instanceof myPromise) return value;
        return new myPromise(resolve => resolve(value));
    }

    static resolvePromise(thenPromise, callBackValue, resolve, reject) {
        if (thenPromise === callBackValue) {
            return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
        }
        if (callBackValue instanceof myPromise) {
            // promise 对象
            callBackValue.then(resolve, reject);
        } else {
            // 普通值
            resolve(callBackValue);
        }
    }
}


